/*
 * File: haptic_hv.c
 *
 * Author: Ethan <renzhiqiang@awinic.com>
 *
 * Copyright (c) 2021 AWINIC Technology CO., LTD
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 */

// #include "main.h"
#include "haptic_hv_reg.h"
#include "haptic_hv.h"
// #include "peripheral_i2c.h"

#define HAPTIC_HV_DRIVER_VERSION			"v0.6.0"

struct aw_haptic_dts *g_dts = NULL;
// 00xdata struct aw_haptic_func *g_func_haptic_hv = NULL;

#ifndef AW_DOUBLE
struct haptic_hv haptic_hv;

struct haptic_hv *g_haptic_hv = &haptic_hv;
#else
struct haptic_hv haptic_hv_l = {
	.i2c_addr = AW_I2C_ADDR_A,
	.rst_pin = AW_RST_Pin_L,
	.f0 = 1700,
	.chipid = 0,
	.ram_num = 0,
	.rtp_cnt = 0,
	.gain = 0x80,
	.duration = 0,
	.timer_ms_cnt = 0,
	.f0_cali_data = 0,
	.osc_cali_data = 0,
	.auto_bst = AW_FALSE,
	.play_mode = AW_RAM_MODE,
	.rtp_play = AW_RTP_PLAY_OFF,
	.vbat_comp = AW_RAM_VBAT_COMP_ENABLE,
	.bst_pc = AW_BST_PC_L1,
	.irq_handle_flag = AW_IRQ_OFF,
};
struct haptic_hv haptic_hv_r = {
	.i2c_addr = AW_I2C_ADDR_B,
	.rst_pin = AW_RST_Pin_R,
	.f0 = 0,
	.chipid = 0,
	.ram_num = 0,
	.rtp_cnt = 0,
	.gain = 0x80,
	.duration = 0,
	.timer_ms_cnt = 0,
	.f0_cali_data = 0,
	.osc_cali_data = 0,
	.auto_bst = AW_FALSE,
	.play_mode = AW_RAM_MODE,
	.rtp_play = AW_RTP_PLAY_OFF,
	.vbat_comp = AW_RAM_VBAT_COMP_ENABLE,
	.bst_pc = AW_BST_PC_L1,
	.irq_handle_flag = AW_IRQ_OFF,
};
struct haptic_hv *g_haptic_hv = &haptic_hv_l;

void haptic_hv_change_motor(aw_motor_name motor_name)
{
	switch (motor_name) {
		case MOTOR_L:
			g_haptic_hv = &haptic_hv_l;
			break;
		case MOTOR_R:
			g_haptic_hv = &haptic_hv_r;
			break;
		default:
			break;
	}
}
#endif

void haptic_hv_1_init(){
	haptic_hv.i2c_addr = AW_I2C_ADDR_A;
	// haptic_hv.rst_pin = AW_RST_Pin;
	haptic_hv.f0 = 0;
	haptic_hv.chipid = 0;
	haptic_hv.ram_num = 0;
	haptic_hv.rtp_cnt = 0;
	haptic_hv.gain = 0x80;
	haptic_hv.duration = 0;
	haptic_hv.timer_ms_cnt = 0;
	haptic_hv.f0_cali_data = 0;
	haptic_hv.osc_cali_data = 0;
	haptic_hv.auto_bst = AW_FALSE;
	haptic_hv.play_mode = AW_RAM_MODE;
	haptic_hv.rtp_play = AW_RTP_PLAY_OFF;
	haptic_hv.vbat_comp = AW_RAM_VBAT_COMP_ENABLE;
	haptic_hv.bst_pc = AW_BST_PC_L1;
	haptic_hv.irq_handle_flag = AW_IRQ_OFF;
}

#ifdef AW_TIKTAP_X
static int haptic_hv_tiktapx_func(struct aw_tiktapx_ctr* params)
{
	struct aw_tiktapx_ctr tiktap_params = *params;
	static uint8_t last_wavseq;
	static uint8_t last_gain;

	if (tiktap_params.play == AW_PLAY_ENABLE) {
		AW_LOGI("play start");
		aw8692x_play_stop();
		aw8692x_play_mode(AW_RAM_LOOP_MODE);
		aw8692x_set_wav_seq(0x00, tiktap_params.wavseq);
		aw8692x_set_wav_seq(0x01, 0x00);
		aw8692x_set_wav_loop(0x00, 0x00);
		aw8692x_set_main_loop(tiktap_params.loop);
		aw8692x_set_gain(tiktap_params.gain);
		aw8692x_play_go(AW_TRUE);
		last_gain = tiktap_params.gain;
		last_wavseq = tiktap_params.wavseq;
	} else if (tiktap_params.play == AW_PLAY_STOP) {
		AW_LOGI("play stop");
		aw8692x_play_stop();
	} else if (tiktap_params.play == AW_PLAY_GAIN) {
		AW_LOGI("play gain");
		if (last_gain != tiktap_params.gain) {
			aw8692x_set_gain(tiktap_params.gain);
			last_gain = tiktap_params.gain;
		}
		if (last_wavseq != tiktap_params.wavseq) {
			aw8692x_set_wav_seq(0x00, tiktap_params.wavseq);
			last_wavseq = tiktap_params.wavseq;
		}
	} else if (tiktap_params.play == AW_PLAY_NULL) {
		AW_LOGI("play null");
		aw8692x_play_stop();
	} else {
		AW_LOGE("play invalid");
		aw8692x_play_stop();
		return AW_ERROR;
	}

	return AW_SUCCESS;
}

static int haptic_hv_tiktapx_interface(uint8_t *p_data, uint16_t length)
{
	struct aw_tiktapx_ctr tiktap_params;
	uint8_t reg_addr = 0;
	uint8_t reg_data = 0;

	if (length != 6) {
		AW_LOGE("tiktap-x params length error!");
		return AW_ERROR;
	}
	tiktap_params.cnt = p_data[0];
	tiktap_params.cmd = p_data[1];
	tiktap_params.play = p_data[2];
	tiktap_params.wavseq = p_data[3];
	tiktap_params.loop = p_data[4];
	tiktap_params.gain = p_data[5];

	AW_LOGI("cnt=%u,cmd=%u,play=%u,wavseq=%u,loop=%u,gain=%u",
		tiktap_params.cnt, tiktap_params.cmd, tiktap_params.play,
		tiktap_params.wavseq, tiktap_params.loop, tiktap_params.gain);

	if (tiktap_params.cmd == AW_CMD_STOP) {
		AW_LOGI("haptic audio off");
		aw8692x_play_stop();
	} else if (tiktap_params.cmd == AW_CMD_ENABLE) {
		AW_LOGI("haptic audio enable");
		if (!((1 <= tiktap_params.cnt) && (tiktap_params.cnt <= 32))) {
			AW_LOGE("cnt value out of range! cnt = %d", tiktap_params.cnt);
			return AW_ERROR;
		}
		if (!(tiktap_params.loop <= AW_LOOP_NUM_MAX)) {
			AW_LOGE("loop value out of range! loop = %d", tiktap_params.loop);
			return AW_ERROR;
		}
		if (!(tiktap_params.gain <= 0x80)) {
			AW_LOGE("gain value out of range! gain = 0x%02x", tiktap_params.gain);
			return AW_ERROR;
		}
		haptic_hv_tiktapx_func(&tiktap_params);
	} else if (tiktap_params.cmd == AW_CMD_RD) {
		reg_addr = tiktap_params.loop;
		haptic_hv_i2c_reads(reg_addr, &reg_data, AW_I2C_BYTE_ONE);
		AW_LOGI("RD: reg_addr = 0x%02x, reg_data = 0x%02x", reg_addr, reg_data);
		return reg_data; /* TODO: Return this parameter to the host algorithm */
	} else if (tiktap_params.cmd == AW_CMD_WR) {
		reg_addr = tiktap_params.loop;
		reg_data = tiktap_params.gain;
		IIC_mem_write_bytes(reg_addr, &reg_data, AW_I2C_BYTE_ONE);
		AW_LOGI("WR: reg_addr = 0x%02x, reg_data = 0x%02x", reg_addr, reg_data);
	} else {
		AW_LOGE("haptic audio invalid cmd");
		aw8692x_play_stop();
		return AW_ERROR;
	}

	return AW_SUCCESS;
}
#endif

static int haptic_hv_get_base_addr(void)
{
	uint16_t last_end = 0;
	uint16_t next_start = 0;
	int i = 0;
	int ram_num = 1;

	for (i = 3; i < haptic_hv_ram_data_len; i = i + 4) {
		last_end = haptic_hv_ram_data[i] << 8 | haptic_hv_ram_data[i + 1];
		next_start = haptic_hv_ram_data[i + 2] << 8 | haptic_hv_ram_data[i + 3];
		if (next_start - last_end == 1)
			ram_num++;
		else
			break;
	}

	for (i = ram_num * 4; i >= 4; i = i - 4) {
		last_end = haptic_hv_ram_data[i - 1] << 8 | haptic_hv_ram_data[i];
		g_haptic_hv->base_addr = (int)(haptic_hv_ram_data[1] << 8 | haptic_hv_ram_data[2]) - ram_num * 4 - 1;
		if (last_end - g_haptic_hv->base_addr + 1 == haptic_hv_ram_data_len) {
			AW_LOGI("base_addr = 0x%04x", g_haptic_hv->base_addr);
			return AW_SUCCESS;
		} else {
			ram_num--;
		}
	}
	return AW_ERROR;
}

static int haptic_hv_ram_init(void)
{
	int i = 0;
	int len = 0;
#ifdef AW_CHECK_RAM_DATA
	int j = 0;
	uint8_t ram_data[AW_RAMDATA_RD_BUFFER_SIZE] = {0};
#endif

	if (haptic_hv_get_base_addr() != AW_SUCCESS) {
		AW_LOGE("base addr error, please check your ram data");
		return AW_ERROR;
	}
	/* RAMINIT Enable */
	aw8692x_raminit_enable(AW_TRUE);
	aw8692x_set_base_addr();
	aw8692x_set_ram_addr();

	AW_LOGI("ram data len is %d", haptic_hv_ram_data_len);
	while (i < haptic_hv_ram_data_len) {
		if ((haptic_hv_ram_data_len - i) < AW_RAMDATA_WR_BUFFER_SIZE)
			len = haptic_hv_ram_data_len - i;
		else
			len = AW_RAMDATA_WR_BUFFER_SIZE;
		aw8692x_set_ram_data(&haptic_hv_ram_data[i], len);
		i += len;
	}

#ifdef AW_CHECK_RAM_DATA
	i = 0;
	aw8692x_set_ram_addr();
	while (i < haptic_hv_ram_data_len) {
		if ((haptic_hv_ram_data_len - i) < AW_RAMDATA_RD_BUFFER_SIZE)
			len = haptic_hv_ram_data_len - i;
		else
			len = AW_RAMDATA_RD_BUFFER_SIZE;
		aw8692x_get_ram_data(ram_data, len);
		for (j = 0; j < len; j++)
			if (ram_data[j] != haptic_hv_ram_data[i + j]) {
				AW_LOGE("check ramdata error, addr=0x%04x, ram_data=0x%02x, file_data=0x%02x", (i + j), ram_data[j], haptic_hv_ram_data[i + j]);
				return AW_ERROR;
			}
		i += len;
	}
	AW_LOGI("check ram data pass");
#endif

	/* RAMINIT Disable */
	aw8692x_raminit_enable(AW_FALSE);

	return AW_SUCCESS;
}

static void haptic_hv_ram_show(void)
{
	uint8_t ram_data[AW_RAMDATA_RD_BUFFER_SIZE] = {0};
	int i = 0;
	int j = 0;
	int size = 0;

	/* RAMINIT Enable */
	aw8692x_raminit_enable(AW_TRUE);
	aw8692x_play_stop();
	aw8692x_set_ram_addr();

	while (i < haptic_hv_ram_data_len) {
		if ((haptic_hv_ram_data_len - i) < AW_RAMDATA_RD_BUFFER_SIZE)
			size = haptic_hv_ram_data_len - i;
		else
			size = AW_RAMDATA_RD_BUFFER_SIZE;
		aw8692x_get_ram_data(ram_data, size);
		for (j = 0; j < size; j++) {
			printf("0x%02x,", ram_data[j]);
			if ((j + 1) % 16 == 0)
				printf("\r\n");
		}
		i += size;
	}
	/* RAMINIT Disable */
	aw8692x_raminit_enable(AW_FALSE);
	printf("\r\n");
}

static void haptic_hv_get_ram_num(void)
{
	uint32_t first_wave_addr = 0;

	first_wave_addr = (haptic_hv_ram_data[1] << 8) | haptic_hv_ram_data[2];
	g_haptic_hv->ram_num = (first_wave_addr - g_haptic_hv->base_addr - 1) / 4;
	AW_LOGI("ram num = %d", g_haptic_hv->ram_num);
}

static int haptic_hv_f0_cali(void)
{
	char f0_cali_lra = 0;
	uint16_t f0_limit = 0;
//	uint16_t f0_cali_min = (g_dts->f0_pre * (100 - g_dts->f0_cali_percent)) / 100;
//	uint16_t f0_cali_max = (g_dts->f0_pre * (100 + g_dts->f0_cali_percent)) / 100;
	uint16_t f0_cali_min = (uint32_t)g_dts->f0_pre * 93UL / 100UL;
	uint16_t f0_cali_max = (uint32_t)g_dts->f0_pre * 107UL / 100UL;
	int f0_cali_step = 0;

	aw8692x_upload_lra(AW_WRITE_ZERO);
	if (aw8692x_get_f0() == AW_ERROR) {
		AW_LOGE("get f0 error, user defafult f0");
	} else {
		/* max and min limit */
		f0_limit = g_haptic_hv->f0;
		AW_LOGE("f0_pre = %d, f0_cali_min = %d, f0_cali_max = %d, f0 = %d",	g_dts->f0_pre, f0_cali_min, f0_cali_max, g_haptic_hv->f0);

		if ((g_haptic_hv->f0 < f0_cali_min) ||
			g_haptic_hv->f0 > f0_cali_max) {
			AW_LOGE("f0 calibration out of range = %d!", g_haptic_hv->f0);
			f0_limit = g_dts->f0_pre;
			return AW_ERROR;
		}
		/* calculate cali step */
		f0_cali_step = (100000L * ((int32_t)f0_limit - (int32_t)g_dts->f0_pre)) /
					   ((int32_t)f0_limit * AW_OSC_CALI_LRA_ACCURACY);
		AW_LOGE("f0_limit = %d, f0_cali_step = %d", (int)f0_limit, f0_cali_step);
		if (f0_cali_step >= 0) {	/*f0_cali_step >= 0 */
			if (f0_cali_step % 10 >= 5)
				f0_cali_step = 32 + (f0_cali_step / 10 + 1);
			else
				f0_cali_step = 32 + f0_cali_step / 10;
		} else {	/* f0_cali_step < 0 */
			if (f0_cali_step % 10 <= -5)
				f0_cali_step = 32 + (f0_cali_step / 10 - 1);
			else
				f0_cali_step = 32 + f0_cali_step / 10;
		}
		if (f0_cali_step > 31)
			f0_cali_lra = (char)f0_cali_step - 32;
		else
			f0_cali_lra = (char)f0_cali_step + 32;
		/* update cali step */
		g_haptic_hv->f0_cali_data = f0_cali_lra;
	}
	aw8692x_upload_lra(AW_F0_CALI_LRA);
	/* restore standby work mode */
	aw8692x_play_stop();
#ifndef AW_F0_CALI_DURING_STARTUP
	haptic_hv_set_cali_to_flash();
#endif
	return AW_SUCCESS;
}

static void haptic_hv_ram_vbat_comp(aw_bool flag)
{
	int temp_gain = 0;

	if (flag) {
		if (g_haptic_hv->vbat_comp == AW_RAM_VBAT_COMP_ENABLE) {
			AW_LOGI("open vbat comp");
			aw8692x_get_vbat();
			temp_gain = g_haptic_hv->gain * AW_VBAT_REFER / g_haptic_hv->vbat;
			if (temp_gain > (128 * AW_VBAT_REFER/AW_VBAT_MIN)) {
				temp_gain = 128 * AW_VBAT_REFER/AW_VBAT_MIN;
				AW_LOGI("gain limit=%d", temp_gain);
			}
		aw8692x_set_gain(temp_gain);
		g_haptic_hv->vbat_comp_gain = temp_gain;
		} else {
			AW_LOGI("close vbat comp");
			aw8692x_set_gain(g_haptic_hv->gain);
		}
	} else {
		aw8692x_set_gain(g_haptic_hv->gain);
		AW_LOGI("close vbat comp");
	}
}

static void haptic_hv_rtp_play(void)
{
	uint8_t  glb_state_val = 0;
	uint16_t buf_len = 0;

	while (!aw8692x_rtp_get_fifo_afs() && (g_haptic_hv->play_mode == AW_RTP_MODE)) {
		/*AW_LOGI("haptic_hv rtp mode fifo update, cnt=%d", g_haptic_hv->rtp_cnt);*/
		/* rtp write data */
		if ((haptic_hv_rtp_data_len - g_haptic_hv->rtp_cnt) < AW_RTP_FRAME_LEN)
			buf_len = haptic_hv_rtp_data_len - g_haptic_hv->rtp_cnt;
		else
			buf_len = AW_RTP_FRAME_LEN;
		aw8692x_set_rtp_data(&haptic_hv_rtp_data[g_haptic_hv->rtp_cnt], buf_len);
		g_haptic_hv->rtp_cnt += buf_len;
		AW_LOGI("rtp_cnt = %d", g_haptic_hv->rtp_cnt);
		glb_state_val = aw8692x_get_glb_state();
		if ((g_haptic_hv->rtp_cnt == haptic_hv_rtp_data_len) || ((glb_state_val & 0x0f) == 0x00)) {
			AW_LOGI("rtp update complete cnt=%d", g_haptic_hv->rtp_cnt);
			AW_LOGI("glb_state_val: 0x%02x", glb_state_val);
			aw8692x_set_rtp_aei(AW_FALSE);
			g_haptic_hv->rtp_cnt = 0;
			g_haptic_hv->rtp_play = AW_RTP_PLAY_OFF;
			break;
		}
	}
}

static int wait_enter_rtp_mode(void)
{
	aw_bool rtp_work_flag = AW_FALSE;
	uint8_t ret = 0;
	int cnt = 200;

	while (cnt) {
		ret = aw8692x_judge_rtp_going();
		if (ret) {
			rtp_work_flag = AW_TRUE;
			AW_LOGI("RTP_GO!");
			break;
		}
		cnt--;
		haptic_hv_mdelay(2);
	}
	if (!rtp_work_flag) {
		aw8692x_play_stop();
		AW_LOGE("failed to enter RTP_GO status!");
		return AW_ERROR;
	}
	return AW_SUCCESS;
}

static void haptic_hv_irq_handle(void)
{
	int irq_state = 0;

	g_haptic_hv->irq_handle_flag = AW_IRQ_OFF;
	haptic_hv_disable_irq();
	do {
		irq_state = aw8692x_get_irq_state();
		if (irq_state == AW_IRQ_ALMOST_EMPTY) {
			AW_LOGI("rtp fifo almost empty int");
			if (g_haptic_hv->rtp_play == AW_RTP_PLAY_ON)
				haptic_hv_rtp_play();
			else{
				AW_LOGI("not in rtp mode!");
			}
		}
		if (g_haptic_hv->play_mode != AW_RTP_MODE)
			aw8692x_set_rtp_aei(AW_FALSE);
	} while (irq_state);
	haptic_hv_enable_irq();
}

static void haptic_hv_vib_work_cancel(void)
{
	/* canel befefore timer handler || rtp */
	if ((g_haptic_hv->timer_ms_cnt != 0) || (g_haptic_hv->rtp_play == AW_RTP_PLAY_ON)) {
		haptic_hv_stop_hrtimer();
		g_haptic_hv->rtp_play = AW_RTP_PLAY_OFF;
		g_haptic_hv->timer_ms_cnt = 0;
	}
	aw8692x_play_stop();
}

static void haptic_hv_rtp_vib_work(aw_gain gain)
{
	haptic_hv_vib_work_cancel();
	/*rtp len*/
	AW_LOGI("rtp file size = %d", haptic_hv_rtp_data_len);
	/*play*/
	g_haptic_hv->rtp_play = AW_RTP_PLAY_ON;
	aw8692x_set_rtp_aei(AW_FALSE);
	aw8692x_irq_clear();
	/* gain */
	aw8692x_set_gain(gain);

	/* rtp mode config */
	aw8692x_play_mode(AW_RTP_MODE);
	aw8692x_upload_lra(AW_WRITE_ZERO);
	/* haptic start */
	aw8692x_play_go(AW_TRUE);
	if (wait_enter_rtp_mode())
		return;
	haptic_hv_rtp_play();
	aw8692x_set_rtp_aei(AW_TRUE);
}

int haptic_hv_short_vib_work(aw_index index, aw_gain gain, aw_loop loop)
{
	if ((loop >= AW_LOOP_NUM_MAX) || (index == 0) || (index > g_haptic_hv->ram_num)) {
		AW_LOGE("loop = %d, index = %d, err", loop, index);
		return AW_ERROR;
	}
	AW_LOGI("start loop = %d, index = %d", loop, index);
	haptic_hv_vib_work_cancel();
	aw8692x_play_mode(AW_RAM_MODE);
	aw8692x_upload_lra(AW_F0_CALI_LRA);
	aw8692x_set_wav_seq(0x00, index);
	aw8692x_set_wav_seq(0x01, 0x00);
	aw8692x_set_wav_loop(0x00, loop - 1);
	aw8692x_set_main_loop(0x00);
	aw8692x_set_gain(gain);
	aw8692x_play_go(AW_TRUE);
	return AW_SUCCESS;
}

static int haptic_hv_long_vib_work(aw_index index, aw_gain gain, uint32_t duration)
{
	if ((duration == 0) || (index == 0) || (index > g_haptic_hv->ram_num)) {
		AW_LOGE("duration = %d, index = %d, err", duration, index);
		return AW_ERROR;
	}
	AW_LOGI("start duration = %d, index = %d", duration, index);
	haptic_hv_vib_work_cancel();
	g_haptic_hv->gain = gain;
	g_haptic_hv->duration = duration;
	aw8692x_upload_lra(AW_F0_CALI_LRA);
	haptic_hv_ram_vbat_comp(AW_TRUE);
	aw8692x_set_wav_seq(0x00, index);
	aw8692x_set_wav_seq(0x01, 0x00);
	aw8692x_set_wav_loop(0x00, 0x0f);
	aw8692x_set_main_loop(0x00);
	aw8692x_play_mode(AW_RAM_LOOP_MODE);
	aw8692x_play_go(AW_TRUE);
	haptic_hv_start_hrtimer();
	return AW_SUCCESS;
}

#ifdef AW_DOUBLE
static int haptic_hv_dual_short_vib_work(aw_index index_l, aw_gain gain_l, aw_loop loop_l,
										 aw_index index_r, aw_gain gain_r, aw_loop loop_r)
{
	haptic_hv_change_motor(MOTOR_L);
	if ((loop_l >= AW_LOOP_NUM_MAX) || (index_l == 0) || (index_l > g_haptic_hv->ram_num)) {
		AW_LOGE("loop_l = %d, index_l = %d, err", loop_l, index_l);
		return AW_ERROR;
	}
	AW_LOGI("start loop_l = %d, index_l = %d", loop_l, index_l);
	haptic_hv_vib_work_cancel();
	aw8692x_play_mode(AW_RAM_MODE);
	aw8692x_upload_lra(AW_F0_CALI_LRA);
	aw8692x_set_wav_seq(0x00, index_l);
	aw8692x_set_wav_seq(0x01, 0x00);
	aw8692x_set_wav_loop(0x00, loop_l - 1);
	aw8692x_set_main_loop(0x00);
	aw8692x_set_gain(gain_l);

	haptic_hv_change_motor(MOTOR_R);
	if ((loop_r >= AW_LOOP_NUM_MAX) || (index_r == 0) || (index_r > g_haptic_hv->ram_num)) {
		AW_LOGE("loop_r = %d, index_r = %d, err", loop_r, index_r);
		return AW_ERROR;
	}
	AW_LOGI("start loop_r = %d, index_r = %d", loop_r, index_r);
	haptic_hv_vib_work_cancel();
	aw8692x_play_mode(AW_RAM_MODE);
	aw8692x_upload_lra(AW_F0_CALI_LRA);
	aw8692x_set_wav_seq(0x00, index_r);
	aw8692x_set_wav_seq(0x01, 0x00);
	aw8692x_set_wav_loop(0x00, loop_r - 1);
	aw8692x_set_main_loop(0x00);
	aw8692x_set_gain(gain_r);

	haptic_hv_change_motor(MOTOR_L);
	aw8692x_play_go(AW_TRUE);
	haptic_hv_change_motor(MOTOR_R);
	aw8692x_play_go(AW_TRUE);
	return AW_SUCCESS;
};

static int haptic_hv_dual_long_vib_work(aw_index index_l, aw_gain gain_l,
									    aw_index index_r, aw_gain gain_r, uint32_t duration)
{
	haptic_hv_change_motor(MOTOR_L);
	if ((duration == 0) || (index_l == 0) || (index_l > g_haptic_hv->ram_num)) {
		AW_LOGE("duration = %d, index_l = %d, err", duration, index_l);
		return AW_ERROR;
	}
	AW_LOGI("start duration = %d, index_l = %d", duration, index_l);
	haptic_hv_vib_work_cancel();
	g_haptic_hv->gain = gain_l;
	g_haptic_hv->duration = duration;
	aw8692x_upload_lra(AW_F0_CALI_LRA);
	haptic_hv_ram_vbat_comp(AW_TRUE);
	aw8692x_set_wav_seq(0x00, index_l);
	aw8692x_set_wav_seq(0x01, 0x00);
	aw8692x_set_wav_loop(0x00, 0x0f);
	aw8692x_set_main_loop(0x00);
	aw8692x_play_mode(AW_RAM_LOOP_MODE);

	haptic_hv_change_motor(MOTOR_R);
	if ((duration == 0) || (index_r == 0) || (index_r > g_haptic_hv->ram_num)) {
		AW_LOGE("duration = %d, index_r = %d, err", duration, index_r);
		return AW_ERROR;
	}
	AW_LOGI("start duration = %d, index_r = %d", duration, index_r);
	haptic_hv_vib_work_cancel();
	g_haptic_hv->gain = gain_r;
	g_haptic_hv->duration = duration;
	aw8692x_upload_lra(AW_F0_CALI_LRA);
	haptic_hv_ram_vbat_comp(AW_TRUE);
	aw8692x_set_wav_seq(0x00, index_r);
	aw8692x_set_wav_seq(0x01, 0x00);
	aw8692x_set_wav_loop(0x00, 0x0f);
	aw8692x_set_main_loop(0x00);
	aw8692x_play_mode(AW_RAM_LOOP_MODE);

	haptic_hv_change_motor(MOTOR_L);
	aw8692x_play_go(AW_TRUE);
	haptic_hv_change_motor(MOTOR_R);
	aw8692x_play_go(AW_TRUE);
	haptic_hv_start_hrtimer();
	return AW_SUCCESS;
}
#endif

static void haptic_hv_set_hw_irq_status(aw_irq aw_hw_irq_handle)
{
	g_haptic_hv->irq_handle_flag = aw_hw_irq_handle;
}

static aw_irq haptic_hv_get_hw_irq_status(void)
{
	return g_haptic_hv->irq_handle_flag;
}

static void haptic_hv_f0_show(void)
{
	aw8692x_upload_lra(AW_WRITE_ZERO);
	aw8692x_get_f0();
	aw8692x_upload_lra(AW_F0_CALI_LRA);
}

static void haptic_hv_cali_show(void)
{
	aw8692x_upload_lra(AW_F0_CALI_LRA);
	aw8692x_get_f0();
}

static void haptic_hv_sw_reset(void)
{
	uint8_t reset = AW_SOFT_RESET;

	AW_LOGI("enter!");
	IIC_mem_write_bytes(AW_REG_RSTCFG, &reset, AW_I2C_BYTE_ONE);
}


static void haptic_hv_hw_reset(void)
{
	AW_LOGI("enter!");
	// haptic_hv_set_reset_gpio(g_haptic_hv->rst_pin, 0);
	// demo_board
	// P00 = 0;

	AW86927_hw_reset(1);
	haptic_hv_mdelay(2);
	AW86927_hw_reset(0);
	// haptic_hv_set_reset_gpio(g_haptic_hv->rst_pin, 1)
	// P00 = 1;
	haptic_hv_mdelay(8);
}

static int haptic_hv_judge_value(uint8_t reg_val)
{
	if (!reg_val)
		return AW_ERROR;
	switch (reg_val) {
	case AW86925_BIT_RSTCFG_PRE_VAL:
	case AW86926_BIT_RSTCFG_PRE_VAL:
	case AW86927_BIT_RSTCFG_PRE_VAL:
	case AW86928_BIT_RSTCFG_PRE_VAL:
	case AW86925_BIT_RSTCFG_VAL:
	case AW86926_BIT_RSTCFG_VAL:
	case AW86927_BIT_RSTCFG_VAL:
	case AW86928_BIT_RSTCFG_VAL:
		return AW_ERROR;
	default:
		break;
	}
	return AW_SUCCESS;
}
uint8_t value[2] = {0};
static int haptic_hv_read_chipid(uint16_t *reg_val)
{
	int ret = AW_SUCCESS;

	/* try the old way of read chip id */
	// value[0] = AW86927_read_byte(AW_REG_CHIPID);
	ret = IIC_mem_read_bytes(AW_REG_CHIPID, &value[0], AW_I2C_BYTE_ONE);
	printf("read chip id first: %hhX ", value[0]);
	if (ret != AW_SUCCESS)
		return ret;

	ret = haptic_hv_judge_value(value[0]);
	if (!ret) {
		*reg_val = value[0];
		return ret;
	}
	// while(1);
	/* try the new way of read chip id */
	haptic_hv_mdelay(1);
	ret = IIC_mem_read_bytes(AW_REG_CHIPIDH, value, AW_I2C_BYTE_TWO);
	if (ret != AW_SUCCESS)
		return ret;
	*reg_val = value[0] << 8 | value[1];
	// while(1);
	return ret;
}

uint16_t reg = 0;
static int haptic_hv_ctrl_init(void)
{
	uint8_t cnt = 0;

	AW_LOGI("enter");
	for (cnt = 0; cnt < AW_READ_CHIPID_RETRIES; cnt++) {
		if (haptic_hv_read_chipid(&reg) != AW_SUCCESS){
			AW_LOGE("read chip id fail");
		}
		switch (reg) {
#ifdef AW869X_DRIVER
		case AW8695_CHIPID:
		case AW8697_CHIPID:
			g_dts = &aw869x_dts;
			// g_func_haptic_hv = &aw869x_func_list;
			return AW_SUCCESS;
#endif
#ifdef AW869XX_DRIVER
		case AW86905_CHIPID:
		case AW86907_CHIPID:
		case AW86915_CHIPID:
		case AW86917_CHIPID:
			g_dts = &aw869xx_dts;
			g_func_haptic_hv = &aw869xx_func_list;
			return AW_SUCCESS;
#endif
#ifdef AW8671X_DRIVER
		case AW86715_CHIPID:
		case AW86716_CHIPID:
		case AW86717_CHIPID:
		case AW86718_CHIPID:
			g_dts = &aw8671x_dts;
			g_func_haptic_hv = &aw8671x_func_list;
			return AW_SUCCESS;
#endif
#ifdef AW8692X_DRIVER
		case AW86925_CHIPID:
		case AW86926_CHIPID:
		case AW86927_CHIPID:
		case AW86928_CHIPID:
			g_dts = &aw8692x_dts;
			// g_func_haptic_hv = &aw8692x_func_list;
			// while(1);
			return AW_SUCCESS;
#endif
		default:
			AW_LOGI("unexpected chipid!");
			break;
		}
		haptic_hv_mdelay(2);
	}
	return AW_ERROR;
}

static void haptic_hv_api_init(void)
{
//	g_func_haptic_hv->f0_cali = haptic_hv_f0_cali;
//	g_func_haptic_hv->long_vib_work = haptic_hv_long_vib_work;
//	g_func_haptic_hv->short_vib_work = haptic_hv_short_vib_work;
//	g_func_haptic_hv->f0_show = haptic_hv_f0_show;
//	g_func_haptic_hv->ram_show = haptic_hv_ram_show;
//	g_func_haptic_hv->cali_show = haptic_hv_cali_show;
//	g_func_haptic_hv->irq_handle = haptic_hv_irq_handle;
//	g_func_haptic_hv->rtp_vib_work = haptic_hv_rtp_vib_work;
//	g_func_haptic_hv->set_hw_irq_status = haptic_hv_set_hw_irq_status;
//	g_func_haptic_hv->get_hw_irq_status = haptic_hv_get_hw_irq_status;
#ifdef AW_TIKTAP_X
	g_func_haptic_hv->tiktapx_interface = haptic_hv_tiktapx_interface;
#endif
#ifdef AW_DOUBLE
	g_func_haptic_hv->dual_short_vib = haptic_hv_dual_short_vib_work;
	g_func_haptic_hv->dual_long_vib = haptic_hv_dual_long_vib_work;
#endif
}

static int haptic_hv_parse_chipid(void)
{
	uint8_t cnt = 0;
	uint16_t reg = 0;
	int ret = AW_SUCCESS;

	for (cnt = 0; cnt < AW_READ_CHIPID_RETRIES; cnt++) {
		ret = haptic_hv_read_chipid(&reg);
		//while(1);
		printf("id: %X\n", reg);
		if (ret != AW_SUCCESS){
			AW_LOGE("failed to read AW_REG_ID: %d", ret);
		}
		switch (reg) {
#ifdef AW869X_DRIVER
		case AW8695_CHIPID:
			g_haptic_hv->chipid = AW8695_CHIPID;
			g_haptic_hv->bst_pc = AW_BST_PC_L1;
			AW_LOGI("reg_val = 0x%02X, detected aw8695.", reg);
			return ret;
		case AW8697_CHIPID:
			g_haptic_hv->chipid = AW8697_CHIPID;
			g_haptic_hv->bst_pc = AW_BST_PC_L2;
			AW_LOGI("reg_val = 0x%02X, detected aw8697.", reg);
			return ret;
#endif
#ifdef AW869XX_DRIVER
		case AW86905_CHIPID:
			g_haptic_hv->chipid = AW86905_CHIPID;
			g_haptic_hv->bst_pc = AW_BST_PC_L1;
			AW_LOGI("reg_val = 0x%02X, detected aw86905.", reg);
			return ret;
		case AW86907_CHIPID:
			g_haptic_hv->chipid = AW86907_CHIPID;
			g_haptic_hv->bst_pc = AW_BST_PC_L2;
			AW_LOGI("reg_val = 0x%02X, detected aw86907.", reg);
			return ret;
		case AW86915_CHIPID:
			g_haptic_hv->chipid = AW86915_CHIPID;
			g_haptic_hv->bst_pc = AW_BST_PC_L1;
			AW_LOGI("reg_val = 0x%02X, detected aw86915.", reg);
			return ret;
		case AW86917_CHIPID:
			g_haptic_hv->chipid = AW86917_CHIPID;
			g_haptic_hv->bst_pc = AW_BST_PC_L2;
			AW_LOGI("reg_val = 0x%02X, detected aw86917.", reg);
			return ret;
#endif
#ifdef AW8671X_DRIVER
		case AW86715_CHIPID:
			g_haptic_hv->chipid = AW86715_CHIPID;
			AW_LOGI("reg_val = 0x%02X, detected aw86715.", reg);
			return ret;
		case AW86716_CHIPID:
			g_haptic_hv->chipid = AW86716_CHIPID;
			AW_LOGI("reg_val = 0x%02X, detected aw86716.", reg);
			return ret;
		case AW86717_CHIPID:
			g_haptic_hv->chipid = AW86717_CHIPID;
			AW_LOGI("reg_val = 0x%02X, detected aw86717.", reg);
			return ret;
		case AW86718_CHIPID:
			g_haptic_hv->chipid = AW86718_CHIPID;
			AW_LOGI("reg_val = 0x%02X, detected aw86718.", reg);
			return ret;
#endif
#ifdef AW8692X_DRIVER
		case AW86925_CHIPID:
			g_haptic_hv->chipid = AW86925_CHIPID;
			g_haptic_hv->bst_pc = AW_BST_PC_L1;
			AW_LOGI("reg_val = 0x%02X, detected aw86925.", reg);
			return ret;
		case AW86926_CHIPID:
			g_haptic_hv->chipid = AW86926_CHIPID;
			g_haptic_hv->bst_pc = AW_BST_PC_L1;
			AW_LOGI("reg_val = 0x%02X, detected aw86926.", reg);
			return ret;
		case AW86927_CHIPID:
			g_haptic_hv->chipid = AW86927_CHIPID;
			g_haptic_hv->bst_pc = AW_BST_PC_L1;
			AW_LOGI("reg_val = 0x%04X, detected aw86927.", reg);
			return ret;
		case AW86928_CHIPID:
			g_haptic_hv->chipid = AW86928_CHIPID;
			g_haptic_hv->bst_pc = AW_BST_PC_L1;
			AW_LOGI("reg_val = 0x%02X, detected aw86928.", reg);
			return ret;
#endif
		default:
			AW_LOGI("unsupport device revision (0x%02X)", reg);
			break;
		}
		haptic_hv_mdelay(2);
	}
	return AW_ERROR;
}

int haptic_hv_boot_init(void)
{
	/* uint8_t reg_val = 0; */
	int ret = AW_SUCCESS;

	haptic_hv_1_init();
	aw8692x_struct_init();

	AW_LOGI("haptic_hv driver version %s", HAPTIC_HV_DRIVER_VERSION);
	haptic_hv_hw_reset();
	ret = haptic_hv_ctrl_init();
	if (ret != AW_SUCCESS) {
		AW_LOGE("please check hardward ad_pin!");
		return ret;
	}
	ret = aw8692x_check_qualify();
	// while(1);
	if (ret != AW_SUCCESS) {
		AW_LOGE("check qualify failed!");
		return ret;
	}
	ret = haptic_hv_parse_chipid();
	if (ret != AW_SUCCESS) {
		AW_LOGE("please check hardward ad_pin!");
		return ret;
	}

	haptic_hv_sw_reset();
	haptic_hv_api_init();

	ret = haptic_hv_ram_init();
	if (ret != AW_SUCCESS) {
		AW_LOGE("ram init err!!!");
		return ret;
	}
	haptic_hv_get_ram_num();
	
	aw8692x_interrupt_setup();
	aw8692x_play_mode(AW_STANDBY_MODE);
	aw8692x_misc_para_init();
	aw8692x_auto_bst_enable(g_haptic_hv->auto_bst);

	/* vbat compensation */
	aw8692x_vbat_mode_config(AW_CONT_VBAT_SW_COMP_MODE);

#ifdef AW_TIKTAP_X
	aw8692x_set_pwm(AW_PWM_12K);
	aw8692x_auto_brake_mode(AW_FALSE);
#else
	aw8692x_set_pwm(AW_PWM_24K);
	aw8692x_auto_brake_mode(AW_TRUE);
#ifdef AW_F0_CALI_DURING_STARTUP
	/* f0 calibration */
	haptic_hv_f0_cali();
#else
	haptic_hv_get_cali_from_flash();
#endif
#endif

	AW_LOGI("end");
	return ret;
}
